package userHelp

import (
	myConfig "common/config"
	"common/helper"
	myredis "common/redis"
	"database/sql"
	"errors"
	"fmt"
	g "github.com/doug-martin/goqu/v9"
	"github.com/shopspring/decimal"
	"lukechampine.com/frand"
	"math"
	"time"
)

// 存款状态
const (
	DepositConfirming    = 361    //确认中
	DepositSuccess       = 362    //存款成功
	DepositCancelled     = 363    //存款已取消
	DepositReviewing     = 364    //存款审核中
	DepositRepairSuccess = 365    //补单成功
	UserNotExist         = "1009" //用户不存在
	DBErr                = "1030" //数据库错误
	OrderStateErr        = "1036" //订单状态异常
	OrderExist           = "1066" //订单已存在
	OrderNotExist        = "1069" //订单不存在
)

// 存款上分
func DepositUpPointSuccess(did, uid, state string) error {

	helper.InfoLog("DepositUpPointSuccess DepositUpPointSuccess ")
	println("DepositUpPointSuccess:", uid)
	// 判断状态是否合法
	allow := map[string]bool{
		fmt.Sprintf(`%d`, DepositSuccess):       true,
		fmt.Sprintf(`%d`, DepositRepairSuccess): true,
	}
	if _, ok := allow[state]; !ok {
		return errors.New(OrderStateErr)
	}

	// 判断订单是否存在
	ex := g.Ex{"id": did, "state": DepositConfirming}
	order, err := depositOrderFindOne(ex)
	if err != nil {
		return err
	}

	// 如果已经有一笔订单补单成功,则其他订单不允许补单成功
	if fmt.Sprintf(`%d`, DepositSuccess) == state {
		// 这里的ex不能覆盖上面的ex
		//_, err = depositOrderFindOne(g.Ex{"oid": order.Oid, "state": DepositSuccess})
		_, err = depositOrderFindOne(g.Ex{"id": order.Id, "state": DepositSuccess})
		if err != nil && err.Error() != OrderNotExist {
			return err
		}

		if err == nil {
			return errors.New(OrderExist)
		}
	}

	money, _ := decimal.NewFromString(order.Amount)

	var isFirst int
	var PromoDepositType int
	TotalDeposit := GetTotalDeposit(uid)
	if TotalDeposit == 0 {
		isFirst = 1
		PromoDepositType = myConfig.PromoDeposit_First
	} else {
		isFirst = 0
		PromoDepositType = myConfig.PromoDeposit_Common
	}

	pdc := myConfig.PromoDepositConfigList(PromoDepositType)

	var discount, bonusAmount decimal.Decimal
	for _, v := range pdc {
		if money.GreaterThanOrEqual(decimal.NewFromFloat(v.MinAmount)) {
			discount = decimal.NewFromFloat(v.Bonus).Div(decimal.NewFromInt(100))

			//计算多少赠送礼金
			bonusAmount = money.Mul(discount)
			if v.MaxAmount > 0 {
				if bonusAmount.GreaterThanOrEqual(decimal.NewFromFloat(v.MaxAmount)) {
					bonusAmount = decimal.NewFromFloat(v.MaxAmount)
				}
			}
			break
		}
	}

	if PromoDepositType == myConfig.PromoDeposit_First && myConfig.IsActiveOpen(myConfig.ActiveType_FirstCharge_Bonus) == 0 {
		bonusAmount = decimal.NewFromFloat(0.00)
	}

	if PromoDepositType == myConfig.PromoDeposit_Common && myConfig.IsActiveOpen(myConfig.ActiveType_RepeatCharge_Bonus) == 0 {
		bonusAmount = decimal.NewFromFloat(0.00)
	}

	ParentId := GetProxyParentId(uid)
	var OrderHidden int = 0
	if isFirst == 0 && (G_UserButton.GetRechargeHiddenSwitch(uid) == 1) && myConfig.GetGameCfgInt(myConfig.CfgRechargeHiddenSwitch) == 1 {
		OrderHidden = 1
	}

	//处理邀请人数
	fDepositMount, _ := money.Float64()
	HiddenMount := GetChargeHiddenMount(uid, int(fDepositMount), PromoDepositType)
	now := time.Now()

	record := g.Record{
		"state":         state,
		"confirm_at":    now.Unix(),
		"confirm_uid":   uid,
		"is_first":      isFirst,
		"Discount":      bonusAmount.InexactFloat64(),
		"Hidden":        OrderHidden,
		"hidden_amount": HiddenMount,
	}

	order.Discount = bonusAmount.InexactFloat64()
	//查询用户是否首存
	LoadUserToRedis(uid)

	query, _, _ := dialect.Update("tbl_deposit").Set(record).Where(ex).ToSQL()
	_, errUpdate := g_sql.Exec(query)

	if errUpdate != nil {
		helper.GetloggerInstance().Emergencyf("%s\n %s", query, errUpdate.Error())
	}

	loc, _ := time.LoadLocation("America/Sao_Paulo")
	deposit := TblDepositPixel{
		Oid:       did,
		Uid:       uid,
		Amount:    order.Amount,
		CreatedAt: now.In(loc).Format(time.DateTime),
		IsFirst:   isFirst,
	}

	insert, _, _ := dialect.Insert("tbl_deposit_pixel").Rows(deposit).ToSQL()
	_, errInsert := g_sql.Exec(insert)
	if errInsert != nil {
		helper.GetloggerInstance().Emergencyf("[insert]:insert sql: %s reason:%s", insert, errInsert.Error())
	}

	cashType := helper.TransactionDeposit

	_, errExec := g_sql.Exec("CALL tbl_report_user_business_deposit_update(?,?,?,?)", uid, fDepositMount, float64(HiddenMount), time.Now().Unix())
	if errExec != nil {
		helper.GetloggerInstance().Emergencyf("CALL tbl_report_user_business_deposit_update(%s,%0.2f,%d);	reason:%s", uid, fDepositMount,
			time.Now().Unix(), errExec.Error())
	}

	//是首存要给上级邀请奖金
	if ParentId != "0" && PromoDepositType == myConfig.PromoDeposit_First {
		FirstDepositToParent(uid, ParentId, fDepositMount, myConfig.GetProxyInviteBonusByDepoistAmount(fDepositMount), 1)

	}

	//充值时 打码全部完成时 临时额度=当前余额
	if TotalDeposit > 0.0 {
		ID := myredis.GetUserFieldInt64(uid, g_tbl_member_wage_require+"ID")
		if ID == 0 {
			//所有任务都已完成
			SetAgencyAmount(uid, GetBalanceFloat64ByUid(uid))
			SetUnlockAmount(uid, GetBalanceFloat64ByUid(uid))
		} else {
			brl := GetBalanceFloat64ByUid(uid)
			unlockAmount := GetUnlockAmount(uid)
			agencyAmount := GetAgencyAmount(uid)

			if brl < unlockAmount {
				SetAgencyAmount(uid, unlockAmount)
			} else if brl >= unlockAmount && brl < agencyAmount {
				SetAgencyAmount(uid, brl)
			}
		}
	}

	AddBalanceTransactionRecord(order.Uid, fDepositMount, cashType, "0", helper.GenId(), 0.00, "", "", 0)
	AddUserWageItem(order.Uid, math.Abs(fDepositMount), cashType)
	AddUserBalanceByDecimal(uid, money)
	if ParentId != "0" {
		helper.InfoLog("HiddenMount:%d", HiddenMount)
		if G_UserButton.GetRechargeButton(ParentId) == 1 {
			RechargeParenShare(uid, ParentId, order.Id, fDepositMount, float64(HiddenMount), 1, isFirst)
		} else {
			RechargeShare(uid, fDepositMount, float64(HiddenMount), order.Id, 1, isFirst)
		}
		grandId := GetProxyGrandId(uid)
		if grandId != "0" {
			if G_UserButton.GetRechargeButton(grandId) == 1 {
				RechargeParenShare(uid, grandId, order.Id, fDepositMount, float64(HiddenMount), 2, isFirst)
			} else {
				RechargeShare(uid, fDepositMount, float64(HiddenMount), order.Id, 2, isFirst)
			}
			greatGrandId := GetProxyGreatGrandId(uid)
			if greatGrandId != "0" {
				if G_UserButton.GetRechargeButton(greatGrandId) == 1 {
					RechargeParenShare(uid, greatGrandId, order.Id, fDepositMount, float64(HiddenMount), 3, isFirst)
				} else {
					RechargeShare(uid, fDepositMount, float64(HiddenMount), order.Id, 3, isFirst)
				}
			}
		}
	}

	if myConfig.GetGameCfgInt(myConfig.CfgDepositBonusManually) == 0 {
		if order.Discount > 0 {
			if TotalDeposit == 0.0 {
				AddBalanceTransactionRecord(uid, order.Discount, helper.TransactionFirstDepositBonus, "0", helper.GenId(), 0.00, "", "", 0)
				AddUserWageItem(uid, order.Discount, helper.TransactionFirstDepositBonus)
				AddUserBalanceByFloat64(uid, order.Discount)
				_, errExec := g_sql.Exec("CALL tbl_report_user_change_update(?,?,?,?)", uid, helper.TransactionFirstDepositBonus, order.Discount, time.Now().Unix())
				if errExec != nil {
					helper.GetloggerInstance().Emergencyf("CALL tbl_report_user_change_update(%s,%d,%0.2f,%d);	reason:%s",
						uid, helper.TransactionFirstDepositBonus, order.Discount, time.Now().Unix(), errExec.Error())
				}
			} else {
				AddBalanceTransactionRecord(uid, order.Discount, helper.TransactionDepositBonus, "0", helper.GenId(), 0.00, "", "", 0)
				AddUserWageItem(uid, order.Discount, helper.TransactionDepositBonus)
				AddUserBalanceByFloat64(uid, order.Discount)
				_, errExec := g_sql.Exec("CALL tbl_report_user_change_update(?,?,?,?)", uid, helper.TransactionDepositBonus, order.Discount, time.Now().Unix())
				if errExec != nil {
					helper.GetloggerInstance().Emergencyf("CALL tbl_report_user_change_update(%s,%d,%0.2f,%d);	reason:%s",
						uid, helper.TransactionDepositBonus, order.Discount, time.Now().Unix(), errExec.Error())
				}
			}

			ex := g.Ex{
				"id": order.Id,
			}
			record := g.Record{
				"is_received": 1,
			}

			query, _, _ := dialect.Update("tbl_deposit").Set(record).Where(ex).ToSQL()
			_, errExec := g_sql.Exec(query)
			if errExec != nil {
				helper.SqlErrLog("[DepositUpPointSuccess]:update sql: %s reason:%s", query, errExec.Error())
			}
		}
	}

	if TotalDeposit == 0 {
		SetFirstDepositAmount(uid, fDepositMount)
		//AddUserDailyAction(uid, Action_FirstDeposit)
	}

	//AddUserDailyAction(uid, Action_Deposit)

	var bValidInvite bool
	bValidInvite = false
	ValidInviteCodition := myConfig.GetGameCfgInt(myConfig.CfgValidInviteCondition)

	//首冲
	if ValidInviteCodition == 0 && TotalDeposit == 0.00 &&
		fDepositMount >= myConfig.GetGameCfgFloat64(myConfig.CfgValidInviteMinDeposit) {
		bValidInvite = true
	}

	//累计
	if ValidInviteCodition > 0 &&
		TotalDeposit < myConfig.GetGameCfgFloat64(myConfig.CfgValidInviteMinDeposit) &&
		(fDepositMount+TotalDeposit) >= myConfig.GetGameCfgFloat64(myConfig.CfgValidInviteMinDeposit) {
		bValidInvite = true
	}

	//有效邀请
	if bValidInvite && GetTotalWaged(uid) >= myConfig.GetGameCfgFloat64(myConfig.CfgValidInviteWagedReq) {
		ProcessValidInvite(uid)
	}

	AddTotalDeposit(uid, fDepositMount)
	AddTotalHiddenDeposit(uid, float64(HiddenMount))
	AddDepositTime(uid, 1)

	//抽奖相关
	AddLottery(uid, fDepositMount)

	LastDepostTime := GetLastDepostTime(uid)
	if LastDepostTime < G_LotteryBaseInfo.BeginTimeStamp {
		fLastLotteryDeposit := GetLotteryDeposit(uid)
		AddLotteryDeposit(uid, -fLastLotteryDeposit)
	}

	AddLotteryDeposit(uid, fDepositMount)

	myredis.ImmediateUpdateRole(uid)
	return nil
}
func ProcessValidInvite(uid string) {

	//增加 有效邀请同IP限制个数 判断
	var ValidInviteIpLimit int
	CfgValidInviteIpLimit := myConfig.GetGameCfgInt(myConfig.CfgValidInviteIpLimit)
	regIp := GetRegIp(uid)

	sqlSelect := fmt.Sprintf("select count(*) from tbl_proxy_base where DonateToParent > 0.0 and regIP='%s'", regIp)
	err := g_sql.Get(&ValidInviteIpLimit, sqlSelect)
	if err != nil {
		helper.SqlSelectErrLog("ProcessValidInvite:%s", sqlSelect)
	}
	ParentId := GetProxyParentId(uid)
	var ProxyInviteBonus float64
	if ParentId != "0" {
		ProxyInviteBonus = GetProxyInviteBonus(ParentId, 0)
	}

	if ValidInviteIpLimit <= CfgValidInviteIpLimit {
		_, errExec := g_sql.Exec("CALL tbl_report_user_business_validInviteNum_update(?,?,?)", uid, 1, time.Now().Unix())
		if errExec != nil {
			helper.GetloggerInstance().Emergencyf("CALL tbl_report_user_business_validInviteNum_update(%s,%d,%d);	reason:%s", uid, 1,
				time.Now().Unix(), errExec.Error())
		}

		if ParentId != "0" && G_UserButton.GetCommiButton(ParentId) == ButtonOpen {
			AddDonateAmountToParent(uid, ProxyInviteBonus)
		}
	}
}
func depositSuccessAmount(uid string) float64 {

	var data sql.NullFloat64
	query, _, _ := dialect.From("tbl_deposit").Select("amount").Where(g.Ex{"uid": uid, "state": DepositSuccess}).Order(g.C("amount").Desc()).Limit(1).ToSQL()
	err := g_sql.Get(&data, query)
	if errors.Is(err, sql.ErrNoRows) {
		return 0
	}

	if err != nil {
		return 0
	}

	return data.Float64
}

// depositOrderFindOne 查询存款订单
func depositOrderFindOne(ex g.Ex) (tblDeposit, error) {

	order := tblDeposit{}
	query, _, _ := dialect.From("tbl_deposit").Select("*").Where(ex).Limit(1).ToSQL()
	err := g_sql.Get(&order, query)
	if err == sql.ErrNoRows {
		return order, errors.New(OrderNotExist)
	}

	if err != nil {
		helper.SqlSelectErrLog("query:%s,\nerr:%s", query, err)
		return order, errors.New(DBErr)
	}

	return order, nil
}

func GenId() string {

	var min uint64 = 0
	var max uint64 = 9

	return fmt.Sprintf("%d%d", Cputicks(), frand.Uint64n(max-min)+min)
}
func Cputicks() (t uint64) {

	sec := time.Now().UnixNano() / 1e6
	return uint64(sec)
}

func getBonusConfig(code string) (TblBonusConfig, error) {

	var data TblBonusConfig
	query, _, _ := dialect.From("tbl_bonus_config").
		Select("*").Where(g.Ex{"code": code}).Limit(1).ToSQL()
	err := g_sql.Get(&data, query)
	if err != nil && !errors.Is(err, sql.ErrNoRows) {
		return data, errors.New(DBErr)
	}

	return data, nil
}

func TurntableSwitch() bool {
	cfgVal := myConfig.GetGameCfgInt(myConfig.CfgTurntableSwitch)

	if cfgVal == 1 {
		return true
	} else {
		return false
	}
}
